package com.spring.AOP;

import com.spring.AOP.AopAnnotation.After;
import com.spring.AOP.AopAnnotation.Around;
import com.spring.AOP.AopAnnotation.Before;
import com.spring.AOP.AopInterface.JoinPoint;
import com.spring.DefaultBeanFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Set;

public  class AopHandler implements InvocationHandler {
    private final Object target; // 原始Bean实例
    private final Map<String,List<MethodInfo>> methodInfoMap;// 原始Bean实例的方法信息
    private final DefaultExecutor defaultExecutor;// 默认执行器
    // 构造方法
    public AopHandler(Object target, Map<Object, Map<Class<?>, List<Method>>> aspectAdviceMap, Map<String, List<MethodInfo>> methodInfoMap, PointCutMatcher pointCutMatcher) {
        this.defaultExecutor = new DefaultExecutor(pointCutMatcher,aspectAdviceMap);
        this.target = target;
        this.methodInfoMap = methodInfoMap;
    }
    //回调方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 如果调用的是Object的方法，直接调用目标对象
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(target, args);
        }
        //  检查是否需要代理
        if (isNeedProxy(method)) {
            // 创建连接点
            JoinPoint joinPoint = new DefaultJoinPoint(target, method, args);
            // 3. 委托给通知执行器处理增强逻辑
            return defaultExecutor.execute(joinPoint);
        }
        // 无需代理，直接执行
        return method.invoke(target, args);
    }
    private boolean isNeedProxy(Method method) {
        String targetClassName = target.getClass().getName();
        List<MethodInfo> methodInfos = methodInfoMap.getOrDefault(targetClassName, List.of());
        // 匹配方法名和参数类型
        return methodInfos.stream()
                .anyMatch(mi -> mi.getMethodName().equals(method.getName()) &&
                        java.util.Arrays.equals(mi.getParameterTypes(), method.getParameterTypes()));
    }

}
